package org.merak.core.text;

import java.text.DateFormatSymbols;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import org.merak.core.annotation.Style;

/**
 * Copyright © 2010-2012 Merak Computing. All rights reserved.<br><br>
 *
 * Private class to be used exclusively inside Context (directly or indirectly) or inside
 * ThreadLocal.
 *
 * @author fmarinho.
 * @version 1.00.00 - Jul 20, 2012 - fmarinho - initial version.
 *
 * @since MerakCore 1.00.00
 */
class Styler {

	//~ Attributes /////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
	private final DecimalFormat    numberFormat = new DecimalFormat();
	private final SimpleDateFormat dateFormat   = new SimpleDateFormat();
	private final StringBuilder    buffer       = new StringBuilder(16);

	//~ Constructors ///////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
	public Styler() {

		this.numberFormat.setDecimalFormatSymbols( DecimalFormatSymbols.getInstance(Locale.US) );
		this.dateFormat.setDateFormatSymbols( DateFormatSymbols.getInstance(Locale.US) );

	}

	//~ Methods ////////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
	public String style(Date object,Style style) {

		// Prepare the localized symbols
		if (!style.locale().isEmpty()) {
			Locale            locale  = new Locale(style.locale());
			DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
			this.dateFormat.setDateFormatSymbols(symbols);
		}

		// Update the pattern and format the date
		this.dateFormat.applyPattern(style.date());
		return this.dateFormat.format(object);

	}
	//**********************************************************************************************
	public String style(Number object,Style style) {

		// Prepare the localized symbols
		if (!style.locale().isEmpty()) {
			Locale               locale  = new Locale(style.locale());
			DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
			this.numberFormat.setDecimalFormatSymbols(symbols);
		}

		// Update the pattern and format the number
		this.numberFormat.applyPattern(style.number());
		return this.numberFormat.format(object);

	}
	//**********************************************************************************************
	public String style(Object object,Style style) {

		// Get or convert to string
		String string = (object instanceof String)
						? (String) object
						: object.toString();

		// Trim it
		if (style.trim()) {
			string = string.trim();
		}

		// Transform it
		switch (style.textTransform()) {
			case LOWERCASE : string = this.toLowerCase(string); break;
			case UPPERCASE : string = this.toUpperCase(string); break;
			case CAPITALIZE: string = this.toCapitalCase(string); break;
		}

		return string;

	}
	//**********************************************************************************************
	private String toUpperCase(String s) {

		// Abort if null string
		if (s == null) return s;

		// Auxiliary
		char ch  = 0;
		int  len = s.length();

		// Prepare the buffer
		this.buffer.setLength(0);
		this.buffer.ensureCapacity(len);

		// Head and tail are uppercase
		for (int i=0; i<len; i++) {
			ch = s.charAt(i);
			this.buffer.append( Character.toUpperCase(ch) );
		}
		return this.buffer.toString();

	}
	//**********************************************************************************************
	private String toLowerCase(String s) {

		// Abort if null string
		if (s == null) return s;

		// Auxiliary
		char ch  = 0;
		int  len = s.length();

		// Prepare the buffer
		this.buffer.setLength(0);
		this.buffer.ensureCapacity(len);

		// Head and tail are uppercase
		for (int i=0; i<len; i++) {
			ch = s.charAt(i);
			this.buffer.append( Character.toLowerCase(ch) );
		}
		return this.buffer.toString();

	}
	//**********************************************************************************************
	private String toCapitalCase(String s) {

		// Abort if null string
		if (s == null || s.isEmpty()) return s;

		// Auxiliary
		char ch  = s.charAt(0);
		int  len = s.length();

		// Prepare the buffer
		this.buffer.setLength(0);
		this.buffer.ensureCapacity(len);

		// Head is uppercase, tail is lowercase
		this.buffer.append( Character.toUpperCase(ch) );
		for (int i=1; i<len; i++) {
			ch = s.charAt(i);
			this.buffer.append( Character.toLowerCase(ch) );
		}
		return this.buffer.toString();

	}
	//**********************************************************************************************
	public String escapeQuote(Object object) {

		// Get or convert to string
		CharSequence string = (object instanceof CharSequence)
							  ? (CharSequence) object
							  : object.toString();

		// Auxiliary
		char ch  = 0;
		int  len = string.length();

		// Prepare the buffer
		this.buffer.setLength(0);
		this.buffer.ensureCapacity(len);

		// Add quotes to string, escaping inner quotes
		for (int i=0; i<len; i++) {
			ch = string.charAt(i);
			if ( ch == '"' ) this.buffer.append('\\');
			this.buffer.append(ch);
		}
		return this.buffer.toString();

	}
	//**********************************************************************************************

}
